home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / proc / procDebug.c < prev    next >
C/C++ Source or Header  |  1992-12-18  |  18KB  |  646 lines

  1. /*
  2.  *  procDebug.c --
  3.  *
  4.  *    Routines to debug a process.  This file maintains a monitor that 
  5.  *    synchronizes access to the debug list.  Routines in this monitor
  6.  *    are responsible for the following fields in the proc table:
  7.  *
  8.  *        PROC_DEBUGGED, PROC_ON_DEBUG_LIST, PROC_SINGLE_STEP_FLAG,
  9.  *           and PROC_DEBUG_WAIT can be set in the genFlags field.
  10.  *
  11.  *    The PROC_DEBUGGED flag is set when a process is being actively debugged
  12.  *    by a debugger.  It is not cleared until a debugger issues the
  13.  *    PROC_DETACH_DEBUGGER debug command.  The PROC_ON_DEBUG_LIST flag is
  14.  *    set when a process is put onto the debug queue and cleared when
  15.  *    it is taken off.
  16.  *
  17.  * Copyright 1986, 1988 Regents of the University of California
  18.  * Permission to use, copy, modify, and distribute this
  19.  * software and its documentation for any purpose and without
  20.  * fee is hereby granted, provided that the above copyright
  21.  * notice appear in all copies.  The University of California
  22.  * makes no representations about the suitability of this
  23.  * software for any purpose.  It is provided "as is" without
  24.  * express or implied warranty.
  25.  */
  26.  
  27. #ifndef lint
  28. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/proc/procDebug.c,v 9.8 92/08/18 11:11:22 jhh Exp $ SPRITE (Berkeley)";
  29. #endif /* not lint */
  30.  
  31. #include <sprite.h>
  32. #include <proc.h>
  33. #include <procInt.h>
  34. #include <procMigrate.h>
  35. #include <status.h>
  36. #include <sync.h>
  37. #include <sched.h>
  38. #include <sys.h>
  39. #include <list.h>
  40. #include <stdlib.h>
  41. #include <vm.h>
  42.  
  43. Sync_Condition    debugListCondition;    /* Condition to sleep on when
  44.                          * waiting for a process to go
  45.                          * onto the debug list. */
  46. static Sync_Lock debugLock;             /* Monitor lock. */
  47. #define LOCKPTR &debugLock
  48.  
  49. List_Links    debugListHdr;
  50. List_Links    *debugList = &debugListHdr;
  51.  
  52. static    ENTRY    void        AddToDebugList _ARGS_((
  53.                     Proc_ControlBlock *procPtr));
  54. static    ENTRY    void        RemoveFromDebugList _ARGS_((
  55.                     Proc_ControlBlock *procPtr));
  56. static    ENTRY    ReturnStatus    ProcGetThisDebug _ARGS_((Proc_PID pid,
  57.                     Proc_ControlBlock **procPtrPtr));
  58. static    ENTRY    ReturnStatus    ProcGetNextDebug _ARGS_((Address destAddr,
  59.                     Proc_ControlBlock **procPtrPtr));
  60.  
  61.  
  62. /*
  63.  *----------------------------------------------------------------------
  64.  *
  65.  * Proc_DebugInit --
  66.  *
  67.  *    Initialize the debug list.
  68.  *
  69.  * Results:
  70.  *    None.
  71.  *
  72.  * Side effects:
  73.  *    The debug list is initialized.
  74.  *
  75.  *----------------------------------------------------------------------
  76.  */
  77.  
  78. void
  79. ProcDebugInit()
  80. {
  81.     List_Init(debugList);
  82.     Sync_LockInitDynamic(&debugLock, "Proc:debugLock");
  83. }
  84.  
  85.  
  86. /*
  87.  *----------------------------------------------------------------------
  88.  *
  89.  * Proc_Debug --
  90.  *
  91.  *    This routine is used to debug a process. This routine is not
  92.  *    inside the monitor. 
  93.  *
  94.  * Results:
  95.  *    SYS_INVALID_ARG -     buffer address was invalid.
  96.  *    PROC_INVALID_PID -     The pid was out-of-range or specified a
  97.  *                non-existent process.
  98.  *    SYS_ARG_NOACCESS -     The buffers were not accessible.
  99.  *
  100.  * Side effects:
  101.  *    The process state and address space may be updated.
  102.  *    A process may be removed from the debug list.
  103.  *
  104.  *----------------------------------------------------------------------
  105.  */
  106.  
  107. ReturnStatus
  108. Proc_Debug(pid, request, numBytes, srcAddr, destAddr)
  109.     Proc_PID         pid;        /* Process id of the process to be 
  110.                      * debugged. */
  111.     Proc_DebugReq     request;     /* Type of action on the debugged 
  112.                      * process. */
  113.     int         numBytes;    /* # of bytes of info to be read or 
  114.                      * written. */
  115.     Address         srcAddr;    /* Location (either in caller or pid) 
  116.                      * where info is to be read. */
  117.     Address         destAddr;    /* Location (either in caller or pid) 
  118.                      * where info info is to be written. */
  119. {
  120.     register Proc_ControlBlock     *procPtr = (Proc_ControlBlock *) NIL;
  121.     Proc_DebugState        debugState;
  122.     int                i;
  123.     ReturnStatus        status = SUCCESS;
  124.     Proc_ControlBlock        *tProcPtr;
  125.  
  126.     /*
  127.      * If the caller is trying to manipulate a debugged process make sure that
  128.      * the process is actually in the debug state.
  129.      */
  130.     if (request != PROC_GET_NEXT_DEBUG && request != PROC_GET_THIS_DEBUG) {
  131.     procPtr = Proc_LockPID(pid);
  132.     if (procPtr == (Proc_ControlBlock *) NIL || 
  133.         !(procPtr->genFlags & PROC_DEBUGGED) ||
  134.         (procPtr->genFlags & PROC_ON_DEBUG_LIST) ||
  135.         procPtr->state != PROC_SUSPENDED ||
  136.         ((procPtr->genFlags & PROC_KILLING) && request==PROC_CONTINUE)) {
  137.         if (procPtr != (Proc_ControlBlock *) NIL) {
  138.         Proc_Unlock(procPtr);
  139.         }
  140.         return (PROC_INVALID_PID);
  141.     }
  142.     }
  143.  
  144.     switch (request) {
  145.     case PROC_GET_THIS_DEBUG:
  146.         status = ProcGetThisDebug(pid, &tProcPtr);
  147.         procPtr = tProcPtr;
  148.         break;
  149.         
  150.     case PROC_GET_NEXT_DEBUG: {
  151.         status = ProcGetNextDebug(destAddr, &tProcPtr);
  152.         procPtr = tProcPtr;
  153.         break;
  154.     }
  155.  
  156.     case PROC_SINGLE_STEP:
  157.             procPtr->genFlags |= PROC_SINGLE_STEP_FLAG;
  158.         procPtr->specialHandling = 1;
  159.         /* Fall through to ... */
  160.         
  161.     case PROC_CONTINUE:
  162.         Sched_MakeReady(procPtr);
  163.         break;
  164.  
  165.     case PROC_GET_DBG_STATE:
  166.  
  167.         debugState.processID    = procPtr->processID;
  168.         debugState.termReason    = procPtr->termReason;
  169.         debugState.termStatus    = procPtr->termStatus;
  170.         debugState.termCode        = procPtr->termCode;
  171.         Mach_GetDebugState(procPtr, &debugState);
  172.         debugState.sigHoldMask    = procPtr->sigHoldMask;
  173.         debugState.sigPendingMask    = procPtr->sigPendingMask;
  174.         for (i = 0; i < SIG_NUM_SIGNALS; i++) {
  175.         debugState.sigActions[i]    = procPtr->sigActions[i];
  176.         debugState.sigMasks[i]        = procPtr->sigMasks[i];
  177.         debugState.sigCodes[i]        = procPtr->sigCodes[i];
  178.         }
  179.  
  180.         if (Vm_CopyOut(sizeof(Proc_DebugState), (Address) &debugState, 
  181.                destAddr)) {
  182.         status = SYS_ARG_NOACCESS;
  183.         }
  184.         break;
  185.  
  186.     case PROC_SET_DBG_STATE:
  187.  
  188.         if (Vm_CopyIn(sizeof(Proc_DebugState), srcAddr, 
  189.                 (Address) &debugState)) {
  190.         status = SYS_ARG_NOACCESS;
  191.         } else {
  192.         Mach_SetDebugState(procPtr, &debugState);
  193.         Sig_ChangeState(procPtr, debugState.sigActions,
  194.                 debugState.sigMasks, debugState.sigPendingMask,
  195.                 debugState.sigCodes, debugState.sigHoldMask);
  196.         }
  197.         break;
  198.  
  199. #define MAX_REQUEST_SIZE 16384
  200.  
  201.     case PROC_READ:
  202.         if (numBytes > MAX_REQUEST_SIZE) {
  203.         status = SYS_INVALID_ARG;
  204.         } else {
  205.         /*
  206.          * Read from the debuggee to the debugger.
  207.          */
  208.         status = Vm_CopyInProc(numBytes, procPtr, srcAddr, 
  209.                        destAddr, FALSE);
  210.         }
  211.  
  212.         break;
  213.  
  214.     case PROC_WRITE:
  215.         if (numBytes > MAX_REQUEST_SIZE) {
  216.         status = SYS_INVALID_ARG;
  217.         break;
  218.         }
  219.  
  220.         /*
  221.          * Make sure that the range of bytes is writable.
  222.          */
  223.         Vm_ChangeCodeProt(procPtr, destAddr, numBytes, TRUE);
  224.         /*
  225.          * Write from the debugger to the debuggee.
  226.          */
  227.         status = Vm_CopyOutProc(numBytes, srcAddr, FALSE,
  228.                     procPtr, destAddr);
  229.         /*
  230.          * Change the protection back.
  231.          */
  232.         Vm_ChangeCodeProt(procPtr, destAddr, numBytes, FALSE);
  233.         Vm_FlushCode(procPtr, destAddr, numBytes);
  234.  
  235.         break;
  236.  
  237.     case PROC_DETACH_DEBUGGER:
  238.         /*
  239.          * Detach from this process.  This has the side effect of 
  240.          * continuing the process as if a resume signal had been sent.
  241.          */
  242.         procPtr->genFlags &= ~(PROC_DEBUGGED | PROC_DEBUG_WAIT);
  243.         Sched_MakeReady(procPtr);
  244.         procPtr->termReason = PROC_TERM_RESUMED;
  245.         procPtr->termStatus = SIG_RESUME;
  246.         procPtr->termCode = SIG_NO_CODE;
  247.         Proc_InformParent(procPtr, PROC_RESUME_STATUS);
  248.         break;
  249.  
  250.     default:
  251.         status = SYS_INVALID_ARG;
  252.         break;
  253.     }
  254.  
  255.     if (status != GEN_ABORTED_BY_SIGNAL && status != PROC_INVALID_PID) {
  256.     Proc_Unlock(procPtr);
  257.     }
  258.  
  259.     return(status);
  260. }
  261.  
  262.  
  263. /*
  264.  *----------------------------------------------------------------------
  265.  *
  266.  * Proc_SuspendProcess --
  267.  *
  268.  *    Put the (current) process into the suspended state.  If the process
  269.  *    is entering the suspended state because of a bug and no process is
  270.  *    debugging it then put it onto the debug list.
  271.  *
  272.  * Results:
  273.  *    None.
  274.  *
  275.  * Side effects:
  276.  *    The process state is changed and the process may be put onto
  277.  *    the debug list. A context switch is performed to the suspend state.
  278.  *
  279.  *----------------------------------------------------------------------
  280.  */
  281. void
  282. Proc_SuspendProcess(procPtr, debug, termReason, termStatus, termCode)
  283.     register    Proc_ControlBlock    *procPtr;    /* Process to put on the
  284.                              * debug list. */
  285.     Boolean                debug;        /* TRUE => this process
  286.                              * is being suspended
  287.                              * because of an 
  288.                              * error. */
  289.     int                    termReason;    /* Reason why process
  290.                              * went to this state.*/
  291.     int                    termStatus;    /* Termination status.*/
  292.     int                    termCode;    /* Termination code. */
  293. {
  294.     Boolean foreign = (procPtr->genFlags & PROC_FOREIGN);
  295.  
  296.     Proc_Lock(procPtr);
  297.     procPtr->genFlags &= ~PROC_PENDING_SUSPEND;
  298.  
  299.     /* 
  300.      * Check whether we lost a race with Proc_ResumeProcess.  If that 
  301.      * happened, just bail out now.
  302.      */
  303.     if (procPtr->genFlags & PROC_RESUME_PROCESS) {
  304.     procPtr->genFlags &= ~PROC_RESUME_PROCESS;
  305.     Proc_Unlock(procPtr);
  306.     return;
  307.     }
  308.  
  309.     procPtr->termReason    = termReason;
  310.     procPtr->termStatus    = termStatus;
  311.     procPtr->termCode    = termCode;
  312.  
  313.     if (debug &&  foreign &&
  314.     proc_KillMigratedDebugs) {
  315.     if (proc_MigDebugLevel > 0) {
  316.         panic("Migrated process being placed on debug list.\n");
  317.     }
  318.     }
  319.  
  320.     if (debug) {
  321.     if (!(procPtr->genFlags & PROC_DEBUGGED)) {
  322.         /*
  323.          * If the process isn't currently being debugged then it goes on 
  324.          * the debug list and its parent is notified of a state change.
  325.          */
  326.         AddToDebugList(procPtr);
  327.         Proc_InformParent(procPtr, PROC_SUSPEND_STATUS);
  328.         ProcDebugWakeup();
  329.     } else if (procPtr->genFlags & PROC_DEBUG_WAIT) {
  330.         /*
  331.          * A process is waiting for this process so wake it up.
  332.          */
  333.         ProcDebugWakeup();
  334.     }
  335.     } else {
  336.     /*
  337.      * The process is being suspended.  Notify the parent and then wakeup
  338.      * anyone waiting for this process to enter the debug state.
  339.      */
  340.     Proc_InformParent(procPtr, PROC_SUSPEND_STATUS);
  341.     if (procPtr->genFlags & PROC_DEBUG_WAIT) {
  342.         ProcDebugWakeup();
  343.     }
  344.     }
  345.     if (foreign) {
  346.     ProcRemoteSuspend(procPtr, PROC_SUSPEND_STATUS);
  347.     }
  348.     Proc_UnlockAndSwitch(procPtr, PROC_SUSPENDED);
  349. }
  350.  
  351.  
  352. /*
  353.  *----------------------------------------------------------------------
  354.  *
  355.  * Proc_ResumeProcess --
  356.  *
  357.  *    Resume execution of the given process.  It is assumed that this 
  358.  *    procedure is called with the process table entry locked.
  359.  *
  360.  * Results:
  361.  *    None.
  362.  *
  363.  * Side effects:
  364.  *    The process may be made runnable and may be removed from the debug list.
  365.  *
  366.  *----------------------------------------------------------------------
  367.  */
  368. void
  369. Proc_ResumeProcess(procPtr, killingProc)
  370.     register    Proc_ControlBlock    *procPtr;    /* Process to remove
  371.                              * from list. */
  372.     Boolean                killingProc;    /* This process is
  373.                              * being resumed for
  374.                              * the purpose of 
  375.                              * killing it. */
  376. {
  377.     /*
  378.      * Only processes that are currently suspended and either are being
  379.      * killed or aren't being actively debugged can be resumed.  If the
  380.      * process has a pending suspend, set a flag in the PCB, which will
  381.      * short-circuit Proc_SuspendProcess.
  382.      * Note: we handle pending suspends this way, rather than simply
  383.      * clearing the pending signal, because the current structure of the
  384.      * sig module doesn't provide strong enough locking using the signals
  385.      * monitor lock.
  386.      */
  387.     
  388.     if (procPtr->state != PROC_SUSPENDED &&
  389.         (procPtr->genFlags & PROC_PENDING_SUSPEND) != 0) {
  390.     procPtr->genFlags |= PROC_RESUME_PROCESS;
  391.     } else if (procPtr->state == PROC_SUSPENDED &&
  392.         (killingProc || !(procPtr->genFlags & PROC_DEBUGGED))) {
  393.     RemoveFromDebugList(procPtr);
  394.     if (procPtr->genFlags & PROC_DEBUGGED) {
  395.         procPtr->genFlags |= PROC_KILLING;
  396.     }
  397.     if (procPtr->genFlags & PROC_DEBUG_WAIT) {
  398.         ProcDebugWakeup();
  399.     }
  400.     procPtr->genFlags &= ~PROC_DEBUG_WAIT;
  401.     Sched_MakeReady(procPtr);
  402.     if (!killingProc) {
  403.         procPtr->termReason = PROC_TERM_RESUMED;
  404.         procPtr->termStatus = SIG_RESUME;
  405.         procPtr->termCode = SIG_NO_CODE;
  406.         /*
  407.          * The parent is notified in background because we are called
  408.          * by the signal code as part of the act of sending a signal
  409.          * and if a SIG_CHILD happens now we will have deadlock.
  410.          * If the process is remote, send the term flags over and
  411.          * let the home node handle signalling the parent.
  412.          */
  413.         if (procPtr->genFlags & PROC_FOREIGN) {
  414.         ProcRemoteSuspend(procPtr, PROC_RESUME_STATUS);
  415.         } else {
  416.         Proc_InformParent(procPtr, PROC_RESUME_STATUS);
  417.         }
  418.     }
  419.     }
  420.  
  421. }
  422.  
  423.  
  424. /*
  425.  *----------------------------------------------------------------------
  426.  *
  427.  * ProcDebugWakeup --
  428.  *
  429.  *    Wakeup any processes waiting on the debug list.
  430.  *
  431.  * Results:
  432.  *    None.
  433.  *
  434.  * Side effects:
  435.  *    None.
  436.  *
  437.  *----------------------------------------------------------------------
  438.  */
  439. ENTRY void
  440. ProcDebugWakeup()
  441. {
  442.     LOCK_MONITOR;
  443.     Sync_Broadcast(&debugListCondition);
  444.     UNLOCK_MONITOR;
  445. }
  446.  
  447. /*
  448.  *----------------------------------------------------------------------
  449.  *
  450.  * ProcGetThisDebug --
  451.  *
  452.  *    Get the specified process on the debug list. If it isn't there
  453.  *    then wait for it to show up.
  454.  *
  455.  *    NOTE: The monitor is not locked until after the PCB is locked
  456.  *    in order to maintain the locking order of other routines
  457.  *    (notably AddToDebugList and RemoveFromDebugList) which grab the
  458.  *    monitor lock after the PCB is locked. This routine used to lock
  459.  *    them in the reverse order causing deadlocks.
  460.  *
  461.  * Results:
  462.  *    PROC_INVALID_PID if process doesn't exist or is dieing.
  463.  *    GEN_ABORTED_BY_SIGNAL if wait for process was interrupted by a 
  464.  *        signal
  465.  *
  466.  *
  467.  * Side effects:
  468.  *    Process may be locked.
  469.  *
  470.  *----------------------------------------------------------------------
  471.  */
  472.  
  473. static ENTRY ReturnStatus
  474. ProcGetThisDebug(pid, procPtrPtr)
  475.     Proc_PID        pid;
  476.     Proc_ControlBlock    **procPtrPtr;
  477. {
  478.     register Proc_ControlBlock     *procPtr;
  479.     ReturnStatus        status;
  480.     Boolean            gotSignal;
  481.  
  482.  
  483.     status = SUCCESS;
  484.     while (TRUE) {
  485.     procPtr = Proc_LockPID(pid);
  486.     if (procPtr == (Proc_ControlBlock *) NIL ||
  487.         (procPtr->genFlags & PROC_DYING)) {
  488.         /*
  489.          * The pid they gave us either doesn't exist or the
  490.          * corresponding process is exiting.
  491.          */
  492.         if (procPtr != (Proc_ControlBlock *) NIL) {
  493.         Proc_Unlock(procPtr);
  494.         }
  495.         status = PROC_INVALID_PID;
  496.         goto exit;
  497.     }
  498.     LOCK_MONITOR;
  499.     procPtr->genFlags |= PROC_DEBUG_WAIT;
  500.  
  501.     if (procPtr->state == PROC_SUSPENDED) {
  502.         procPtr->genFlags &= ~PROC_DEBUG_WAIT;
  503.         procPtr->genFlags |= PROC_DEBUGGED;
  504.         if (procPtr->genFlags & PROC_ON_DEBUG_LIST) {
  505.         List_Remove((List_Links *) procPtr);
  506.         procPtr->genFlags &= ~PROC_ON_DEBUG_LIST;
  507.         }
  508.         UNLOCK_MONITOR;
  509.         goto exit;
  510.     }
  511.  
  512.     Proc_Unlock(procPtr);
  513.     gotSignal = Sync_Wait(&debugListCondition, TRUE);
  514.     UNLOCK_MONITOR;
  515.     if (gotSignal) {
  516.         Proc_Lock(procPtr);
  517.         procPtr->genFlags &= ~PROC_DEBUG_WAIT;
  518.         Proc_Unlock(procPtr);
  519.         status = GEN_ABORTED_BY_SIGNAL;
  520.         goto exit;
  521.     }
  522.     }
  523. exit:
  524.     *procPtrPtr = procPtr;
  525.     return(status);
  526. }
  527.  
  528. /*
  529.  *----------------------------------------------------------------------
  530.  *
  531.  * ProcGetNextDebug --
  532.  *
  533.  *    Look through the list of debuggable processes and get the
  534.  *    first one that hasn't been debugged yet. Wait for one if
  535.  *    there aren't any.
  536.  *
  537.  * Results:
  538.  *    SYS_ARG_NOACCESS if data couldn't be copied to user address space.
  539.  *    GEN_ABORTED_BY_SIGNAL if wait for process was interrupted by a 
  540.  *        signal
  541.  *
  542.  * Side effects:
  543.  *    Process is removed from list, process id is copied to user 
  544.  *    variable.  Process is locked unless GEN_ABORTED_BY_SIGNAL is 
  545.  *    returned.
  546.  *
  547.  *----------------------------------------------------------------------
  548.  */
  549.  
  550. static ENTRY ReturnStatus
  551. ProcGetNextDebug(destAddr, procPtrPtr)
  552.     Address        destAddr;
  553.     Proc_ControlBlock    **procPtrPtr;
  554. {
  555.     Boolean            sigPending = FALSE;
  556.     register Proc_ControlBlock     *procPtr = (Proc_ControlBlock *) NIL;
  557.     ReturnStatus        status;
  558.  
  559.  
  560.     LOCK_MONITOR;
  561.  
  562.     status = SUCCESS;
  563.     while (!sigPending) {
  564.     if (!List_IsEmpty(debugList)) {
  565.         procPtr = (Proc_ControlBlock *) List_First(debugList);
  566.         Proc_Lock(procPtr);
  567.         procPtr->genFlags |= PROC_DEBUGGED;
  568.         List_Remove((List_Links *) procPtr);
  569.         procPtr->genFlags &= ~PROC_ON_DEBUG_LIST;
  570.         break;
  571.     }
  572.     sigPending = Sync_Wait(&debugListCondition, TRUE);
  573.     }
  574.     if (!sigPending) {
  575.     if ((Vm_CopyOut(sizeof(Proc_PID), 
  576.           (Address) &procPtr->processID, destAddr)) != SUCCESS){
  577.         status = SYS_ARG_NOACCESS;
  578.     }
  579.     } else {
  580.     status = GEN_ABORTED_BY_SIGNAL;
  581.     }
  582.     *procPtrPtr = procPtr;
  583.     UNLOCK_MONITOR;
  584.     return(status);
  585. }
  586.  
  587. /*
  588.  *----------------------------------------------------------------------
  589.  *
  590.  * AddToDebugList --
  591.  *
  592.  *    Adds the given process to the debug list.
  593.  *
  594.  * Results:
  595.  *    None.
  596.  *
  597.  * Side effects:
  598.  *    Process is added to list, process genFlags is modified.
  599.  *
  600.  *----------------------------------------------------------------------
  601.  */
  602.  
  603. static ENTRY void
  604. AddToDebugList(procPtr)
  605.     register Proc_ControlBlock     *procPtr;
  606. {
  607.     LOCK_MONITOR;
  608.  
  609.     List_Insert((List_Links *) procPtr, LIST_ATREAR(debugList));
  610.     procPtr->genFlags |= PROC_ON_DEBUG_LIST;
  611.  
  612.     UNLOCK_MONITOR;
  613. }
  614.  
  615. /*
  616.  *----------------------------------------------------------------------
  617.  *
  618.  * RemoveFromDebugList --
  619.  *
  620.  *    Removes the given process from the debug list.
  621.  *
  622.  * Results:
  623.  *    None.
  624.  *
  625.  * Side effects:
  626.  *    The process is removed from the list, process's genFlags field
  627.  *    is modified.
  628.  *
  629.  *----------------------------------------------------------------------
  630.  */
  631.  
  632. static ENTRY void
  633. RemoveFromDebugList(procPtr)
  634.     register Proc_ControlBlock     *procPtr;
  635. {
  636.     LOCK_MONITOR;
  637.  
  638.     if (procPtr->genFlags & PROC_ON_DEBUG_LIST) {
  639.     List_Remove((List_Links *) procPtr);
  640.     procPtr->genFlags &= ~PROC_ON_DEBUG_LIST;
  641.     }
  642.  
  643.     UNLOCK_MONITOR;
  644. }
  645.  
  646.